package benchmark;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

import utils.MissingArgumentException;
import utils.Tools;
import utils.Tools.OutputType;

public abstract class AbstractBenchmarkMT extends AbstractBenchmark {

	private final static String THREAD_NUM = "tnum";

	public AbstractBenchmarkMT(String[] args) throws Exception {
		super(args);
		this.argReadme.put(THREAD_NUM, "Thread number.");
		System.out.println("t number:" + getThreadNum());
	}
	
	public int getThreadNum() throws MissingArgumentException {
		return (int) getArg(THREAD_NUM);
	}
	
	private List<Callable<Long>> callables;
	private List<Future<Long>> results;
	
	private ExecutorService executor;
	
	protected abstract List<Callable<Long>> initRunnables();


	@Override
	protected void benchmark(String name, long cycles) throws Exception {
		callables = initRunnables();
		results = new ArrayList<Future<Long>>();
		executor = Executors.newFixedThreadPool(getThreadNum() + 1);	
		Tools.output(name, OutputType.MARK_START);
		long counter = cycles;
		long sum = 0;
		long start = System.nanoTime();
		while (counter-- > 0) {
			for (Callable<Long> c : callables) {
				results.add(executor.submit(c));
			}
		}
		executor.shutdown();
		while (!executor.isTerminated()) {
			// TODO: need sleep?
		}

		long elapse = System.nanoTime() - start;
		
		for (Future<Long> f : results) {
			sum += f.get();
		}
		
		Tools.output(Long.toString(sum), OutputType.REDUNDANCE);
		Tools.output(Long.toString(elapse / cycles), OutputType.RESULT);
		Tools.output(name, OutputType.MARK_END);
	}

}
